package ChannelTutorial.Demo04;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.StandardCharsets;

/**
 * Demo04 - Channel 生命周期详解 - 服务端
 * 
 * 学习目标：
 * 1. 理解 Channel 的完整生命周期
 * 2. 掌握各个生命周期回调方法的触发时机
 * 3. 了解生命周期状态转换
 * 4. 学习如何在不同阶段进行资源管理
 */
@Slf4j
public class Server {

    public static void main(String[] args) {
        log.info("=== Channel 生命周期演示 - 服务端 ===\n");
        
        new Thread(() -> {
            try {
                startServer();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
    }

    /**
     * 启动服务端
     */
    private static void startServer() throws Exception {
        EventLoopGroup boss = new NioEventLoopGroup(1);
        EventLoopGroup worker = new NioEventLoopGroup();
        
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(boss, worker)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) {
                        ch.pipeline().addLast(new ServerLifecycleHandler());
                    }
                });
            
            ChannelFuture bindFuture = serverBootstrap.bind(8080).sync();
            log.info("[服务端] 已启动，监听端口 8080\n");
            log.info("[服务端] 请运行 Client.java 客户端进行测试\n");
            
            bindFuture.channel().closeFuture().sync();
            
        } finally {
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }
    }

    /**
     * 服务端生命周期处理器
     */
    @Slf4j
    static class ServerLifecycleHandler extends ChannelInboundHandlerAdapter {
        
        private int connectionId;
        private static int counter = 0;
        
        public ServerLifecycleHandler() {
            this.connectionId = ++counter;
        }

        @Override
        public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
            log.info("🟢 [服务端-{}] 1. handlerAdded - Handler 被添加到 Pipeline", connectionId);
        }

        @Override
        public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
            log.info("🟢 [服务端-{}] 2. channelRegistered - Channel 注册到 EventLoop", connectionId);
            ctx.fireChannelRegistered();
        }

        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            log.info("🟢 [服务端-{}] 3. channelActive - Channel 激活（连接建立）", connectionId);
            log.info("   [服务端-{}] 远程地址: {}", connectionId, ctx.channel().remoteAddress());
            
            // 发送欢迎消息
            ctx.writeAndFlush(
                Unpooled.copiedBuffer("Welcome! Connection " + connectionId, StandardCharsets.UTF_8)
            );
            
            ctx.fireChannelActive();
        }

        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            log.info("🟢 [服务端-{}] 4. channelRead - 读取数据", connectionId);
            
            ByteBuf buf = (ByteBuf) msg;
            String data = buf.toString(StandardCharsets.UTF_8);
            log.info("   [服务端-{}] 收到: {}", connectionId, data);
            
            // 回复数据
            ctx.writeAndFlush(
                Unpooled.copiedBuffer("Server received: " + data, StandardCharsets.UTF_8)
            );
            
            buf.release();
        }

        @Override
        public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
            log.info("🟢 [服务端-{}] 5. channelReadComplete - 本次读取完成", connectionId);
            ctx.fireChannelReadComplete();
        }

        @Override
        public void channelInactive(ChannelHandlerContext ctx) throws Exception {
            log.info("🔴 [服务端-{}] 6. channelInactive - Channel 失活（连接断开）", connectionId);
            ctx.fireChannelInactive();
        }

        @Override
        public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
            log.info("🔴 [服务端-{}] 7. channelUnregistered - Channel 从 EventLoop 注销", connectionId);
            ctx.fireChannelUnregistered();
        }

        @Override
        public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
            log.info("🔴 [服务端-{}] 8. handlerRemoved - Handler 从 Pipeline 移除", connectionId);
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            log.error("❌ [服务端-{}] exceptionCaught - 发生异常: {}", 
                connectionId, cause.getMessage());
            ctx.close();
        }
    }
}

/*
=== 运行结果分析 ===

1. 完整的生命周期顺序：

   创建阶段：
   1. handlerAdded      - Handler 添加到 Pipeline
   2. channelRegistered - Channel 注册到 EventLoop
   3. channelActive     - Channel 激活（连接建立）

   工作阶段：
   4. channelRead          - 读取数据（可能多次）
   5. channelReadComplete  - 本次读取完成（可能多次）

   销毁阶段：
   6. channelInactive      - Channel 失活（连接断开）
   7. channelUnregistered  - Channel 从 EventLoop 注销
   8. handlerRemoved       - Handler 从 Pipeline 移除

2. 生命周期状态转换：

   ChannelUnregistered
         ↓
   ChannelRegistered  (channelRegistered)
         ↓
   ChannelActive      (channelActive)
         ↓
   ← channelRead/channelReadComplete （循环）
         ↓
   ChannelInactive    (channelInactive)
         ↓
   ChannelUnregistered (channelUnregistered)

3. 关键时机：

   - handlerAdded：初始化 Handler 的状态
   - channelActive：连接建立，可以开始发送数据
   - channelRead：处理接收到的数据
   - channelInactive：连接断开，清理资源
   - handlerRemoved：释放 Handler 占用的资源

=== 最佳实践 ===

✅ 在 channelActive 中初始化连接相关资源
✅ 在 channelInactive 中清理资源
✅ 在 channelRead 中及时释放 ByteBuf
✅ 在 exceptionCaught 中记录日志并关闭连接

❌ 不要在 channelActive 之前发送数据
❌ 不要忘记调用 fireXXX() 传播事件
❌ 不要在 channelInactive 后继续使用 Channel
❌ 不要泄露资源（ByteBuf、文件句柄等）
*/

